package negotiator;

import java.awt.Frame;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.JOptionPane;

import lombok.Data;

import org.apache.log4j.Logger;

import producer.bean.OrderInfo;
import producer.bean.ProductRequiredBean;
import producer.impl.Producer;
import product.impl.Product;
import algorithms.AlgorithManager;
/**
 * Globalny negocjator dla producentow
 * @author Przemek Pioro
 *
 */
@Data
public class Negotiator extends Thread {
	private Frame frame;
	private List<Producer> producers;
	static final Logger log = Logger.getLogger(Negotiator.class);
	private static LinkedList<OrderBean> orders = new LinkedList<OrderBean>();
	private Map<String, List<OrderBean>> orderMap = new HashMap<String, List<OrderBean>>();
	private Map<Producer,OrderInfo> negotiationInfo = new HashMap<Producer,OrderInfo>();
	private static Producer mainProducer;
	private static int WAIT_TIME = 10000;


	@Override
	public void run() {
		while (true) {
			WaitForOrders();
			if (!orders.isEmpty()) {
				analizeOrders();
				for (String productName : orderMap.keySet()) {
					log.info("Analizuje zamowienia dla przedmiotu. nazwa: " + productName);
					int count = getProductCount(productName);
					if (mainProducer.isProductAvaible(new Product(productName,count, mainProducer.getCategory()))) {
						mainProducer.executeOrder(productName, count);
						JOptionPane.showMessageDialog(frame, "Produkt "+ productName + ". Zostal kupiony");
					} else {
						Producer finder = find(mainProducer.getProductRequierd(productName),count);
						if (finder !=null){
							finder.executeOrder(mainProducer.getProductRequierd(productName).getName(),count*mainProducer.getProductRequierd(productName).getCount());
							mainProducer.executeOrder(productName, count);
							JOptionPane.showMessageDialog(frame, "Produkt "+ productName + ". Zostal kupiony");			
						}			
					}

				}
			}
		}
	}
	
	private Producer  find(ProductRequiredBean required,int count){
		if(required !=null){
			for(Producer producer : producers){
				if(producer.getProductNames().contains(required.getName())){
					log.info("Negocjuje z producentem nazwa: "+producer.getName());
					OrderInfo value = producer.measuredOrder(required.getName(),required.getCount()*count);
					negotiationInfo.put(producer, value);
				}
			}
			log.info("Znalazlem producenta.Kończe działanie");
			return AlgorithManager.analize(negotiationInfo);
			}
		return null;
	}	
	
	/**
	 * Analizuje zamowiania od producentow
	 */
	private void analizeOrders() {
		for (int i = 0; i < orders.size(); i++) {
			OrderBean bean = orders.removeFirst();
			if (mainProducer == null) {
				mainProducer = bean.getProducer();
			}
			if (!orderMap.containsKey(bean.getProduct().getName())) {
				List<OrderBean> list = new ArrayList<OrderBean>();
				list.add(bean);
				orderMap.put(bean.getProduct().getName(), list);
			} else {
				orderMap.get(bean.getProduct().getName()).add(bean);
			}

		}
	}
	

	private int getProductCount(String productName) {
		int count = 0;
		for (OrderBean bean : orderMap.get(productName)) {
			count += bean.getProduct().getCount();
		}
		return count;

	}
	
	public static void setProducer(Producer p){
		 mainProducer = p;
	}
	
	/**
	 * Dodaje zamowienie do kolejki
	 * @param order
	 */
	public static synchronized void addOrder(OrderBean order) {
		orders.addLast(order);
	}
	/**
	 * Metoda oczekujaca na zamowienia
	 */
	private void WaitForOrders() {
		try {
			Thread.sleep((long) (WAIT_TIME));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	/**
	 * Zmienia czas oczekiwania
	 * @param time
	 */
	public static void changeWaitTime(int time){
		WAIT_TIME = time*1000;
	}
}
